/*   The MIT License
 *   
 *   Carina Engine
 *   Copyright (c) 2009 2010 2011 2012 Zdravko Velinov
 *   
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#include "carina/post-processing.hh"

namespace Carina
{
PostProcessing::PostProcessing(const GraphicsEngineContextPtr& ce_ctx)
    :   m_Renderer(ce_ctx->getWindow()->getRenderer())
{
    m_Framebuffers[0] = m_Renderer->createFramebuffer();
    m_Framebuffers[1] = m_Renderer->createFramebuffer();
    
    resize(ce_ctx->getWindow()->getWidth(), ce_ctx->getWindow()->getHeight());

    m_State = m_Renderer->createStateObject(MiscStateDescription(CE_FILL_SOLID, CE_CULL_NONE));
    m_BlendState = m_Renderer->createBlendStateObject(BlendStateDescription(false));
    m_DepthStencilState = m_Renderer->createDepthStencilStateObject(DepthStencilStateDescription(false, false));
}

PostProcessing::PostProcessing(const RendererPtr& renderer, size_t width, size_t height)
    :   m_Renderer(renderer)
{
    m_Framebuffers[0] = renderer->createFramebuffer();
    m_Framebuffers[1] = renderer->createFramebuffer();
    
    resize(width, height);
}

PostProcessing::~PostProcessing()
{
}

void PostProcessing::setupFramebuffer()
{
    m_Renderer->bindFramebuffer(m_PostProcPass.empty() ? FramebufferPtr() : m_Framebuffers[0]);
}

void PostProcessing::postProcess()
{
    ScopedState state(m_Renderer, m_State);
    ScopedBlendState blend(m_Renderer, m_BlendState);
    ScopedDepthStencilState dsstate(m_Renderer, m_DepthStencilState);

    for(size_t i = 0; i < m_PostProcPass.size(); ++i)
    {
        m_Renderer->useShaderProgram(m_PostProcPass[i].program);
        m_Renderer->bindDrawFramebuffer(i + 1 < m_PostProcPass.size() ? m_Framebuffers[(i+1)%2] : FramebufferPtr());
        m_PostProcPass[i].input_texture->set(m_Textures[i%2]);
        m_Renderer->setVideoBuffer(VideoBufferPtr(), 0, 0);
        m_Renderer->setIndexBuffer(VideoBufferPtr(), IT_USHORT, 0);
        m_Renderer->setInputLayout(InputLayoutConstPtr());
        m_Renderer->draw(CE_TRIANGLE_STRIP, 0, 4);
    }
}

void PostProcessing::registerPostProcProgram(const PostProcessingPass& post_proc)
{
    m_PostProcPass.push_back(post_proc);
}

void PostProcessing::resize(size_t width, size_t height)
{
    FBAttachmentArray arr[2];
    m_Textures[0] = m_Renderer->createTexture(TextureDescription(width, height, 1, VT_RGBA8_UNORM), nullptr, 0);
    arr[0].push_back(FBAttachmentInfo(m_Textures[0]));
    m_Framebuffers[0]->attachTextures(arr[0]);
    m_Framebuffers[0]->attachDepthStencilTexture(FBAttachmentInfo(m_Renderer->createTexture(TextureDescription(width, height, 1, VT_D24S8), nullptr, 0)));
    m_Textures[1] = m_Renderer->createTexture(TextureDescription(width, height, 1, VT_RGBA8_UNORM), nullptr, 0);
    arr[1].push_back(FBAttachmentInfo(m_Textures[1]));
    m_Framebuffers[1]->attachTextures(arr[1]);
}
}